package transclusion;

import java.util.ArrayList;
import java.util.Collections;

import processing.core.*;
import transclusion.items.*;
import treemap.*;

public class Path {
	public PApplet papplet;	
	ArrayList<Itemable> path;
	
	public Path(PApplet p) {
		papplet = p;		
		path = new ArrayList<Itemable>();
	}
	
	public boolean inactive() {
		SourceItem item = nextItem();
		if(item == null)
			return true;
		return ( path.isEmpty() );
	}
	
	public boolean active() {
		return !inactive();
	}
	
	public void invalidate() {
		//debug
		//PApplet.println("invalidating path");
		path.clear();
	}
	
	public boolean busy() {
		//only active paths can be busy
		if(inactive())
			return false;
		return ((UniverseVisualization)papplet).zoomBounds.targeting;
	}
	
	public void setPath(Category cat) {
		path.clear();
		//CategoryItem zoomItem = ((UniverseVisualization)papplet).zoomItem;
		ArrayList<Category.IndexedItem> catDescendants = ((UniverseVisualization)papplet).catDescendants;
		//ArrayList<Article.IndexedItem> artDescendants = ((UniverseVisualization)papplet).artDescendants;
		int index = catDescendants.indexOf(cat);
		if(index >= 0)
			setPathFromIndexedCategory(index);
	}
	
	/**
     * Warning: {@code ((Category)zoomItem.item).articleDescendants(catDescendants, artDescendants)}
     * should be called from the caller before calling this method.
     */
    public void setPath(Article art) {
    	path.clear();
		CategoryItem zoomItem = ((UniverseVisualization)papplet).zoomItem;
		ArrayList<Category.IndexedItem> catDescendants = ((UniverseVisualization)papplet).catDescendants;
		ArrayList<Article.IndexedItem> artDescendants = ((UniverseVisualization)papplet).artDescendants;
		//((Category)zoomItem.item).articleDescendants(catDescendants, artDescendants);
		int index = artDescendants.indexOf(art);
		if(index >= 0)
			setPathFromIndexedArticle(index);
	}    
    
    /**
     * Warning: {@code ((Category)zoomItem.item).articleDescendants(catDescendants, artDescendants)}
     * should be called from the caller before calling this method.
     */
    public void setPathFromIndexedCategory(int index) {
    	path.clear();
    	CategoryItem zoomItem = ((UniverseVisualization)papplet).zoomItem;
    	ArrayList<Category.IndexedItem> catDescendants = ((UniverseVisualization)papplet).catDescendants;
		ArrayList<Article.IndexedItem> artDescendants = ((UniverseVisualization)papplet).artDescendants;
    	//((Category)zoomItem.item).articleDescendants(catDescendants, artDescendants);
    	//debug
    	//print();
    	
    	if(index < 0 || index >= catDescendants.size() )
    		return;
		int i = index;
		while(i != -1) {
			Itemable.IndexedItem indexItem = catDescendants.get(i);
			path.add( indexItem.item );
			i = indexItem.index;			
		}
		path.add(zoomItem.item);
		Collections.reverse(path);
		
		//debug
		//printPath();
    }
    
    /**
     * Warning: {@code ((Category)zoomItem.item).articleDescendants(catDescendants, artDescendants)}
     * should be called from the caller before calling this method.
     */
    public void setPathFromIndexedArticle(int index) {
    	path.clear();
    	CategoryItem zoomItem = ((UniverseVisualization)papplet).zoomItem;
    	ArrayList<Category.IndexedItem> catDescendants = ((UniverseVisualization)papplet).catDescendants;
		ArrayList<Article.IndexedItem> artDescendants = ((UniverseVisualization)papplet).artDescendants;
    	//((Category)zoomItem.item).articleDescendants(catDescendants, artDescendants);		
    	//debug
    	//print();
    	
    	if(index < 0 || index >= artDescendants.size() )
    		return;
    	
    	Itemable.IndexedItem indexItem = artDescendants.get(index);
    	path.add( indexItem.item );    	
    	
		int i = indexItem.index;
		while(i != -1) {
			indexItem = catDescendants.get(i);
			path.add( indexItem.item );
			i = indexItem.index;			
		}
		path.add(zoomItem.item);
		Collections.reverse(path);
		
		//debug
		//printPath();
    }   
    
    public SourceItem nextItem() {
    	SourceItem result = null;
    	CategoryItem zoomItem = ((UniverseVisualization)papplet).zoomItem;
    	String name = zoomItem.name;
    	int i;
    	for ( i=0; i < path.size(); i++ ) {
    		if( path.get(i).name() == name )
    			break;
    	}
    	
    	if( i < (path.size()-1) ) {
    		name = path.get(i+1).name();
    		ArrayList<Mappable> list = zoomItem.getArrayItems();
    		for( Mappable m : list ) {
    			if( ((SourceItem)m).name == name) {
    				result = (SourceItem)m;
    				break;
    			}
    		}
    	}
    	
    	return result;
    }
    
    // debug
    public void print() {
    	CategoryItem zoomItem = ((UniverseVisualization)papplet).zoomItem;
    	ArrayList<Category.IndexedItem> catDescendants = ((UniverseVisualization)papplet).catDescendants;
		ArrayList<Article.IndexedItem> artDescendants = ((UniverseVisualization)papplet).artDescendants;
    	if(catDescendants != null) {
			PApplet.println("Category descendants of " + zoomItem.item.name() );
			for( Category.IndexedItem cat : catDescendants )
				PApplet.print("(" + cat.item.name() + " ," + cat.index + ") ");
		}
    	PApplet.println();
		if(artDescendants != null) {
			PApplet.println("Article descendants of " + zoomItem.item.name() );
			for( Article.IndexedItem art : artDescendants )
				PApplet.print("(" + art.item.name() + " ," + art.index + ") ");
		}				
		PApplet.println();
    }
    
    public void printPath() {
    	if(path != null)
    		if( path.size() > 0 ) {
    			PApplet.println("path:");
    			for ( Itemable item : path )
    				if ( item.isCategory() )
    					PApplet.print( item.name() + " (category) -> " );
    				else
    					PApplet.print( item.name() + " (article) -> " );
    		}
    	PApplet.println();
    }
}
